import dlib,os,glob,time
import  cv2
import numpy as np
import csv
import pandas as pd
import math
from scipy.spatial.distance import pdist
import matplotlib.pyplot as plt

class Recognition():

    #计算128D描述符的欧式距离
    def compute_dst(self,feature_1,feature_2):
        feature_1 = np.array(feature_1)
        feature_2 = np.array(feature_2)
        #dist1 = pdist(np.vstack([feature_1,feature_2]),'cosine')
        dist = np.linalg.norm(feature_1 - feature_2)
        return dist

    def get_facelibrary(self):
        featuremean_path = "./dataset/task1/featureMean/"
        if not os.path.exists(featuremean_path):
            os.mkdir(featuremean_path)
        head = [] # 没有表头的会导致将内容认为是表头
        for i in range(128):
            fe = "feature_" + str(i + 1)
            head.append(fe)

        face_path = featuremean_path+"feature_all.csv"
        face_feature=pd.read_csv(face_path,names=head)

        # print(face_feature.shape)

        face_feature_array=np.array(face_feature)
        #print(face_feature_array.shape)
        return face_feature_array

    # 图像增强算法
    def sharpen(self,gray):
        kernel_sharpen = np.array([
                        [-0.5, -0.5, -0.5],
                        [-0.5, 5, -0.5],
                        [-0.5, -0.5, -0.5]])   # 参数可以修改
        output = cv2.filter2D(gray, -1, kernel_sharpen)
        return output

    def strength(self,gray):
        Imin, Imax = cv2.minMaxLoc(gray)[:2]
        # Imax = np.max(img)
        # Imin = np.min(img)
        Omin, Omax = 0, 255
        # 计算a和b的值
        a = float(Omax - Omin) / (Imax - Imin)
        b = Omin - a * Imin
        out = a * gray + b
        out = out.astype(np.uint8)
        cv2.imshow("img", gray)
        cv2.imshow("out", out)

    def gamma_strength(self,gray):
        fi = gray / 255.0  #图像归一化
        gamma = 0.8  # 该参数可以调整，越接近一，则差异化越小
        out = np.power(fi, gamma)
        return out

    def linear_strength(self,gray):
        out = 2.0 * gray  # 该系数可以进行调整
        out[out > 255] = 255
        out = np.around(out)
        out = out.astype(np.uint8)
        return out

    def normalization_strength(self,gray):
        Imin, Imax = cv2.minMaxLoc(gray)[:2]
        # Imax = np.max(img)
        # Imin = np.min(img)
        Omin, Omax = 0, 255
        # 计算a和b的值
        a = float(Omax - Omin) / (Imax - Imin)
        b = Omin - a * Imin
        out = a * gray + b
        out = out.astype(np.uint8)
        return out



    def face_recognition(self,image):
        # 加载检测关键点定位和识别模型
        predictor_path = "./dataset/task1/model/shape_predictor_68_face_landmarks.dat"
        model_path = "./dataset/task1/model/dlib_face_recognition_resnet_model_v1.dat"

        detector = dlib.get_frontal_face_detector() # 框选人脸
        # 人脸关键点标记
        predictor= dlib.shape_predictor(predictor_path) # 返回68个特征点的位置
        # 生成面部识别器
        facerec = dlib.face_recognition_model_v1(model_path)
        
        face_mean = np.zeros(128)
        
        F,H,W,_ = image.shape
        count = np.zeros(20)
        finish = 0                    
        for i in range(F):
            if i % 6== 0: 
                finish += 1          # 每6帧截取一帧
                # 转为灰度图像处理
                gray = cv2.cvtColor(image[i,:,:,:], cv2.COLOR_BGR2GRAY)
                #print(np.array(gray).astype)
                #gray = sharpen(gray) 
                dets = detector(gray, 1)
                #print(dets)        # 检测帧图像中的人脸
                # 处理检测到的每一张人脸
                if len(dets)>0:
                    for Index,value in enumerate(dets): # 返回检测区域的矩形坐标
                        #获取面部关键点
                        shape = predictor(gray,value)
                        # 提取特征-图像中的68个关键点转换为128D面部描述符
                        face_descriptor = facerec.compute_face_descriptor(image[i,:,:,:], shape)
                        v = np.array(face_descriptor)
                        ID,index = self.Result(v,self.get_facelibrary())
                        count[index] += 1 # 记录被分到每一个类别的帧数
                # print("已识别该视频帧数的{:.0f}%".format(finish/(math.floor(F/6)+(F%6!=0))*100))
        Maxindex = np.argmax(count)
            #face_mean = face_mean+v
    #face_mean = face_mean/(math.floor(F/6))
    #return face_mean
        return Maxindex

    def Result(self,face_mean,face_feature_array): # 返回ID
        face_list = ["ID1","ID10","ID11","ID12","ID13","ID14","ID15","ID16","ID17","ID18","ID19","ID2","ID20","ID3","ID4","ID5","ID6","ID7","ID8","ID9"] # 根据遍历顺序得到
        #for i in range(1,21,1):
        #face_list.append("ID{}".format(i))
        distance_list = [] # 存储到各个平均特征的距离
        for i in range(20):
            distance_list.append(self.compute_dst(face_mean,face_feature_array[i]))

        result_ = distance_list.index(min(distance_list)) # 返回最小距离的索引
        result = face_list[result_]

        return result,result_







